package ai.llmchat.common.security.service.impl;

import ai.llmchat.common.core.exception.AuthenticationException;
import ai.llmchat.common.security.SecurityClaims;
import ai.llmchat.common.security.service.TokenStoreService;
import cn.hutool.core.util.IdUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.Assert;

import java.util.Optional;
import java.util.concurrent.TimeUnit;

public class TokenStoreServiceImpl implements TokenStoreService {
    private static final String TOKEN_KEY_PREFIX = "token:";
    private final RedisTemplate<String, SecurityClaims> redisTemplate;

    public TokenStoreServiceImpl(RedisTemplate<String, SecurityClaims> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public String store(SecurityClaims claims) {
        Assert.notNull(claims, "claims can not be null");
        String token = IdUtil.fastUUID();
        String key = formatKey(token);
        redisTemplate.opsForValue().set(key, claims, 7, TimeUnit.DAYS);
        return token;
    }

    @Override
    public SecurityClaims read(String token) {
        Assert.notNull(token, "token can not be empty");
        String key = formatKey(token);
        SecurityClaims claims = redisTemplate.opsForValue().get(key);
        if (Optional.ofNullable(claims).map(SecurityClaims::getId).orElse(0L) <= 0) {
            throw new AuthenticationException("Token已过期，请重新登录");
        }
        return claims;
    }

    @Override
    public String readAndRefresh(String token) {
        Assert.notNull(token, "token can not be empty");
        String key = formatKey(token);
        SecurityClaims claims = redisTemplate.opsForValue().getAndExpire(key, 7, TimeUnit.DAYS);
        if (Optional.ofNullable(claims).map(SecurityClaims::getId).orElse(0L) <= 0) {
            throw new AuthenticationException("Token已过期，请重新登录");
        }
        return claims.getUsername();
    }

    @Override
    public void remove(String token) {
        String key = formatKey(token);
        redisTemplate.delete(key);
    }

    private String formatKey(String token) {
        return TOKEN_KEY_PREFIX + token;
    }
}
